전체 포스트

배열과 튜플 타입에 대해 알아보자

배열과 튜플 타입에 대해 알아봅니다
2/13/2023 작성

개요

안녕하세요 이정환입니다😃

이번에는 타입스크립트는 배열 타입과 튜플 타입에 대해 살펴보겠습니다.

배열

배열 타입은 다음과 같이 간단하게 명시할 수 있습니다.

COPY
let numArr: number[] = [1, 2, 3];

number[] 처럼 배열에 저장할 타입을 형태로 숫자를 저장하는 배열임을 명시합니다.

number 타입의 값들을 저장하는 배열 타입임을 명시했기 때문에 다른 타입의 값을 저장하려고 하면 오류가 발생합니다.

COPY
let numArr: number[] = [1, 2, 3, true];
// 오류: boolean 형식은 number에 할당 불가

만약 number 타입 값을 저장하는 배열이 아니라 string 타입 값을 저장하는 배열을 만들고 싶다면 다음과 같이 할 수 있습니다.

COPY
let numArr: number[] = [1, 2, 3];
let strArr: string[] = ["1", "2", "3"];

또는 다음과 같은 문법으로도 배열 타입을 명시할 수 있습니다.

COPY
let numArr: Array<number> = [1, 2, 3];
let strArr: Array<string> = ["1", "2", "3"];

참고로 이때 사용하는 Array 타입은 타입스크립트가 기본적으로 제공하는 내장 타입입니다.

단 Array 타입은 다음과 같이 단독으로는 사용할 수 없습니다.

COPY
let arr: Array = [];
// 오류 : Array<T>' 제네릭 형식에 1 형식 인수가 필요합니다.

Array 타입은 꼭 <>를 사용하고 그 안에 배열 요소의 타입을 명시하는 타입을 넣어주어야 하는데 이런 문법을 ‘제네릭’이라고 합니다. 이후에 자세히 다룹니다.

COPY
let arr: Array<string> = [];
// 오류 : Array<T>' 제네릭 형식에 1 형식 인수가 필요합니다.

다차원 배열 타입 선언하기

프로그래밍을 하다 보면 다차원 배열을 사용하는 경우가 존재합니다.

타입스크립트에서는 매우 간단하게 다차원 배열 타입을 선언할 수 있습니다.

COPY
const multiArr: string[][] = [
  ["1", "2"],
  ["3", "4", "5"],
];

string[][] 타입은 string 타입 값들을 저장하는 배열을 저장하는 배열을 의미합니다. 추가적인 차원이 필요하다면 []를 한번 더 붙이면 됩니다. 3차원 배열을 사용할 일이 흔하지는 않으므로 자세한 코드는 생략합니다.

이렇듯 타입스크립트에서는 간단하게 다차원 배열 타입을 선언할 수 있습니다.

튜플

다음으로 살펴볼 타입은 ‘튜플’ 타입입니다.

파이썬을 사용해본 사람이라면 익숙한 타입이겠으나, 자바스크립트만 사용해본 학습자라면 아마 처음 들어본 타입일 겁니다.

튜플은 자바스크립트에는 존재하지 않지만 타입스크립트가 제공하는 새로운 타입입니다.

튜플은 길이와 타입이 고정된 배열 타입을 의미합니다.

자바스크립트의 배열은 길이와 타입이 고정되어 있지 않습니다. 따라서 무한대로 요소를 추가할 수 있고 다양한 타입의 값을 저장할 수 있습니다. 이런 배열에 길이와 타입의 제한을 추가한 타입이 바로 튜플입니다.

예를 들어 튜플을 이용하면 길이는 2이고 number 타입의 값만 저장하는 배열타입을 선언할 수 있습니다.

튜플 기본 사용법

튜플 타입은 다음과 같이 선언합니다.

COPY
let tuple: [number, number] = [1, 2];

[number, number] 형식으로 선언된 튜플 타입은 딱 두개의 숫자 값을 저장하는 배열을 의미합니다.

따라서 다음과 같이 3개의 숫자 값을 저장하는 배열을 저장하려고 하면 오류가 발생합니다.

COPY
let tuple: [number, number] = [1, 2, 3];
// 오류 : '[number, number, number]' 형식은 '[number, number]' 형식에 할당할 수 없습니다.
// 소스에 3개 요소가 있지만, 대상에서 2개만 허용합니다.

오류 메세지를 보면 “소스에 3개의 요소가 있지만, 2개만 허용한다”라고 하여 tuple 변수의 타입은 딱 2개의 숫자 값을 저장하는 배열만 허용 됨을 알 수 있습니다.

다음과 같이 다양한 타입의 값을 저장하는 튜플을 선언할 수도 있습니다.

COPY
let tuple: [number, string, boolean] = [1, "str", true];

[number, string, boolean] 으로 선언된 튜플 타입은 한개의 숫자 값, 한개의 문자열 값, 한개의 불리언 값을 저장한 배열 타입을 의미합니다.

튜플 타입에 명시된 순서대로 값을 저장하지 않아도 오류가 발생합니다.

COPY
let tuple: [number, string, boolean] = ["str", 1, true];
// 오류 : 'string' 형식은 'number' 형식에 할당할 수 없습니다.

튜플은 왜 필요할까요?

그렇다면 튜플이라는 타입은 왜 타입스크립트에 추가된 걸까요?

다음과 같이 유저들의 정보를 저장하는 2차원 배열이 있다고 가정하겠습니다.

COPY
const users = [
  ["이정환", 1],
  ["이아무개", 2],
  ["김아무개", 3],
  ["박아무개", 4],
];

users에 저장되는 한개의 배열은 한명의 유저 정보를 배열로 저장하고 있습니다. 또 배열의 첫번째 요소에는 이름, 두번째 요소에는 유저 고유 번호를 저장합니다.

다음으로 users에 저장된 유저들의 고유 번호를 순차적으로 콘솔에 출력하는 함수 printUserNumbers가 있다고 가정합니다.

COPY
const users = [
  ["이정환", 1],
  ["이아무개", 2],
  ["김아무개", 3],
  ["박아무개", 4],
];

function printUserNumbers() {
  for (let i = 0; i < users.length; i++) {
    console.log(users[i][1]);
  }
}

printUserNumbers();
// 1 2 3 4

이때 만약 규칙을 잘 모르는 개발자가 새로운 유저를 추가하기 위해 users에 다음과 같이 새로운 요소를 추가했다고 가정하겠습니다.

COPY
const users = [
  ["이정환", 1],
  ["이아무개", 2],
  ["김아무개", 3],
  ["박아무개", 4],
  [5, "조아무개"], // 새로이 추가함
];

function printUserNumbers() {
  for (let i = 0; i < users.length; i++) {
    console.log(users[i][1]);
  }
}

printUserNumbers();
// 1 2 3 4 조아무개

물론 눈치가 조금이라도 있다면 실제로 저렇게 추가 하지는 않겠지만 너무 정신없이 코딩한 나머지 이런 실수를 저질렀다고 가정하겠습니다.

그럼 printUserNumbers 함수에서는 유저들의 고유 번호를 출력해야 하는데 이름을 출력하게 되어 결국 의도대로 동작하지 않게 됩니다.

이런 상황에 타입스크립트의 튜플 타입을 이용하면 쉽게 실수를 방지할 수 있습니다.

COPY
const users: [string, number][] = [
  ["이정환", 1],
  ["이아무개", 2],
  ["김아무개", 3],
  ["박아무개", 4],
  [5, "조아무개"], // 오류!
];

(...)

[string, number] 타입 튜플을 저장하는 배열 타입을 [string, number][] 와 같은 형식으로 선언합니다.

그러면 [5, “조아무개”]는 [string, number] 형식의 튜플 타입에 할당할 수 없으므로 오류가 발생합니다.

이제 규칙을 잘 모르는 개발자더라도 본인이 작성한 코드에 빨간줄로 오류가 나타나니 무엇이 문제인지 바로 파악할 수 있을 겁니다.

튜플도 결국 배열입니다.

아쉽게도 튜플은 컴파일하면 그냥 자바스크립트 배열로 변환됩니다.

다음과 같이 index.ts를 수정한 다음 tsc로 컴파일 합니다.

COPY
const tup: [number, string] = [1, "2"];

컴파일 결과 다음과 같은 자바스크립트 코드가 생성됩니다.

COPY
"use strict";
var tup = [1, "2"];

따라서 튜플도 결국 배열입니다. 그렇기 때문에 한가지 한계점이 존재하는데 바로 push 메서드를 사용해도 오류를 감지하지 못한다는 점 입니다.

COPY
const tup: [number, string] = [1, "2"];
tup.push(10);
tup.push(10);

console.log(tup);

// [ 1, '2', 10, 10 ]

tup의 타입은 분명 길이가 2로 고정된 튜플이지만 push 메서드로 2번이나 숫자 값을 배열에 추가해도 오류가 발생하지 않습니다. 따라서 ts-node를 이용해 index.ts를 실행하면 tup의 값은 [1, ‘2’, 10, 10]으로 출력됩니다.

 

이렇듯 타입스크립트는 튜플 이라는 특수한 타입을 제공합니다. 이를 이용해 고정된 길이의 배열 타입을 선언할 수 있습니다. 튜플 타입은 생각보다 활용도가 많아 자주 이용하게 되니 꼭 기억해두시길 바랍니다.